using System;
using System.Collections.Generic;
using System.Linq;
using OrangeProject.ReactiveList.Core.Communication;
using OrangeProject.ReactiveList.Core.Entities;

namespace OrangeProject.ReactiveList.Core.Client
{
    public abstract class DataContext : IDisposable
    {
        public event Action Updated;
        private ITransportCore _transportCore;
        public List<AbstractReactiveList> Lists { get; set; } = new List<AbstractReactiveList>();
        public Dictionary<String, Action> _UpdateActions { get; } = new Dictionary<string, Action>();
        
        protected DataContext(ITransportCore transportCore)
        {
            _transportCore = transportCore;
            _transportCore.DataContext = this;
            
            _transportCore.ReceiveState(receivedBody =>
            {
                Lists.ForEach(list =>
                {
                    list.RestoreObjectAddDeleteStates(receivedBody.Data.Single(container => container.Name == list.Name));
                });
                
                Lists.ForEach(list =>
                {
                    list.RestoreObjectUpdateState(receivedBody.Data.Single(container => container.Name == list.Name));
                });
                
                receivedBody.Data.ForEach(container =>
                {
                    var item = Lists.SingleOrDefault(list => list.Name == container.Name) as ReactiveList<IEntity>;
                    if (item != null)
                    {
                        if (container.Updated.Length > 0) item._Updated.Invoke(container.Updated);
                        if (container.Created.Length > 0) item._Created.Invoke(container.Created);
                        if (container.Deleted.Length > 0) item._Deleted.Invoke(container.Deleted);
                        
                        Updated?.Invoke();
                    }
                });
                if (_UpdateActions.ContainsKey(receivedBody.Guid))
                {
                    _UpdateActions[receivedBody.Guid]?.Invoke();
                    _UpdateActions.Remove(receivedBody.Guid);
                }
                
            });
        }

        public void SaveChanges(Action action = null)
        {
            var states = Lists.Select(list => list.LookupObjectStates()).ToList();
            
            var sendingBody = new DataBody
            {
                Data = states,
                Guid = Guid.NewGuid().ToString(),
                Parameters = new Dictionary<string, object>()
            };
            
            _UpdateActions.Add(sendingBody.Guid, action);
            _transportCore.SendState(sendingBody, SendTo.Server);
        }

        public void DiscardChanges()
        {
            Lists.ForEach(item => item.DiscardChanges());
        }

        public void Dispose()
        {
            _transportCore.Dispose();
            _UpdateActions.Clear();
        }
    }
}


